package gui;

import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import calculate.Add;
import calculate.BinaryOperator;
import calculate.Division;
import calculate.Minus;
import calculate.Multiply;
import calculate.UnaryOperator;

/**
 * This class implements the basic version of the calculator which supports only
 * the basic operation (+,-,*,/) and no functional keys are provided.
 * 
 * Pay attention that this version assumes that all the input is legal and
 * provide no illegal input detection and defense.
 * 
 * @author Jacky Xu
 *
 */
public class BasicCalculator extends Calculator {

	private double operand = 0;
	private boolean flag = true;

	public BasicCalculator() {
		super();

		JFrame frame = new JFrame("Calculator");
		frame.setBounds(700, 300, 450, 650);

		GridBagLayout gbaglayout = new GridBagLayout(); // GridBagLayout
		GridBagConstraints constraints = new GridBagConstraints();
		frame.setLayout(gbaglayout);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		constraints.fill = GridBagConstraints.BOTH;
		constraints.weightx = 0.0;
		constraints.gridwidth = GridBagConstraints.REMAINDER;

		setConstrain(constraints, 0, 0, 4, 1, 0.5, 0.5);
		gbaglayout.setConstraints(line1, constraints);
		frame.add(line1);

		setConstrain(constraints, 0, 1, 4, 2, 0.5, 0.5);
		gbaglayout.setConstraints(line2, constraints);
		frame.add(line2);

		setConstrain(constraints, 0, 3, 4, 4, 2, 2);
		gbaglayout.setConstraints(this.keyboard, constraints);
		frame.add(this.keyboard);

		frame.setVisible(true);
	}

	@Override
	protected HashMap<String, BinaryOperator> getBiOperator() {
		HashMap<String, BinaryOperator> bio = new HashMap<String, BinaryOperator>();
		bio.put("-", new Minus());
		bio.put("+", new Add());
		bio.put("×", new Multiply());
		bio.put("÷", new Division());

		return bio;
	}

	@Override
	protected HashMap<String, UnaryOperator> getUnOperator() {
		HashMap<String, UnaryOperator> uo = new HashMap<String, UnaryOperator>();
		return uo;
	}

	@Override
	protected List<String> getFunctional() {
		return new ArrayList<String>();
	}

	@Override
	protected String[] getKeys() {
		String[] keys = { "7", "8", "9", "÷", "4", "5", "6", "×", "1", "2", "3", "-", "0", ".", "+", "=" };

		return keys;
	}

	@Override
	protected JPanel getKeyboard(Font f) {
		JPanel keyboard = new JPanel();
		keyboard.setLayout(new GridLayout(4, 4, 0, 0));

		for (String key : this.keys) {
			JButton button = new JButton(key);
			button.setFont(f);
			button.addActionListener(e -> {
				String command = e.getActionCommand();
				Parser(command);
			});
			keyboard.add(button);
		}

		return keyboard;
	}

	@Override
	protected void Parser(String command) {
		if (this.numbers.contains(command)) {
			// a number button is pressed
			buffer += command;
			this.line2.setText(buffer);
		} else if (command.equals(".")) {
			// the dot button is pressed
			if (flag) {
				// if there is no former dot
				buffer += command;
				this.line2.setText(buffer);
				flag = false;
			}
		} else if (this.binaryoperators.keySet().contains(command)) {
			// a binary operator button is pressed
			if (buffer.equals("")) {
				this.pre_opt = command;
				this.line1.setText(String.valueOf(this.operand) + command);
			} else {
				if (this.pre_opt.equals("")) {
					this.pre_opt = command;
					this.operand = Double.valueOf(buffer);
					buffer = "";
					flag = true;
					this.line1.setText(String.valueOf(this.operand) + command);
				} else {
					BinaryOperator opt = binaryoperators.get(this.pre_opt);
					this.pre_opt = command;
					double a = Double.valueOf(buffer);
					buffer = "";
					flag = true;
					double result = opt.calculate(operand, a);

					this.operand = result;
					this.line1.setText(String.valueOf(result) + command);
					this.line2.setText(String.valueOf(result));
				}
			}
		} else if (command.contentEquals("=")) {
			// the = button is pressed
			if (buffer.equals("")) {
				this.pre_opt = "";
				this.line1.setText(String.valueOf(this.operand) + "=");
				this.line2.setText(String.valueOf(this.operand));
			} else {
				double a = buffer.equals(".") ? 0 : Double.valueOf(buffer);
				buffer = "";
				flag = true;

				if (this.pre_opt.contentEquals("")) {
					this.operand = a;
					this.line1.setText(String.valueOf(operand) + "=");
					this.line2.setText(String.valueOf(a));

				} else {

					double result = this.binaryoperators.get(this.pre_opt).calculate(this.operand, a);

					this.line1.setText(String.valueOf(operand) + pre_opt + String.valueOf(a) + "=");
					this.line2.setText(String.valueOf(result));

					this.pre_opt = "";
					this.operand = result;
				}

			}
		}
	}

	public static void main(String[] args) {
		new BasicCalculator();
	}
}
